/** FASSIT (Forms of Selective Attention in Intelligent Transportation Systems)
 * Computational Creativity and Digital Media
 * Cognitive and Media Systems Group
 * Centre for Informatics and Systems of the University of Coimbra (CISUC)
 *
 * Copyright (c) 2010-2013 University of Coimbra, Portugal
 * All rights reserved.
 */
package agent.Metrics.Uncertainty;

import poi.Uncertainty.*;

/**
 * This class is used to evaluate the metric of Uncertainty
 * 
 * @author Hernani Costa
 * @version 0.1 date: 28/01/2013
 */
public class UncertaintyEvaluator {

	private static UncertaintyEvaluator instance;

	/**
	 * ------------------------------------------------------------------------
	 * Constructor class
	 * ------------------------------------------------------------------------
	 */
	public synchronized static UncertaintyEvaluator getInstance() {
		if (instance == null)
			instance = new UncertaintyEvaluator();
		return instance;
	}

	/**
	 * ------------------------------------------------------------------------
	 * Evaluates the Uncertainty value for the parameter DaysOff
	 * ------------------------------------------------------------------------
	 * 
	 * @param agent
	 *            - Agent's knowledge for the parameter DaysOff
	 * @param master
	 *            - Real Knowledge for the parameter DaysOff
	 * @return - Uncertainty value for the parameter DaysOff
	 */
	public synchronized double evaluatingDaysOff(UncertaintyDaysOff agent,
			UncertaintyDaysOff master) {

		double[] valuesAgent = { agent.getMonday(), agent.getTuesday(),
				agent.getWednesday(), agent.getThursday(), agent.getFriday(),
				agent.getSaturday(), agent.getSunday() };

		double[] valuesMaster = { master.getMonday(), master.getTuesday(),
				master.getWednesday(), master.getThursday(),
				master.getFriday(), master.getSaturday(), master.getSunday() };

		double number = valuesAgent.length;

		double prior = calcEventResult(valuesAgent[0])
				+ calcEventResult(valuesAgent[1])
				+ calcEventResult(valuesAgent[2])
				+ calcEventResult(valuesAgent[3])
				+ calcEventResult(valuesAgent[4])
				+ calcEventResult(valuesAgent[5])
				+ calcEventResult(valuesAgent[6]);

		double post = calcEventResult(valuesMaster[0])
				+ calcEventResult(valuesMaster[1])
				+ calcEventResult(valuesMaster[2])
				+ calcEventResult(valuesMaster[3])
				+ calcEventResult(valuesMaster[4])
				+ calcEventResult(valuesMaster[5])
				+ calcEventResult(valuesMaster[6]);

		//System.out.println("\n\nAgent: " + agent.to_String());
		//System.out.println("Master: " + master.to_String());


		double result = (prior - post) / Math.log(number);
		//System.out.println("result: " + result + "\n\n");

		return result;

	}

	/**
	 * ------------------------------------------------------------------------
	 * Evaluates the Uncertainty value for the parameter Price
	 * ------------------------------------------------------------------------
	 * 
	 * @param agent
	 *            - Agent's knowledge for the parameter Price
	 * @param master
	 *            - Real Knowledge for the parameter Price
	 * @return - uncertainty value for the parameter Price
	 */
	public synchronized double evaluatingPrice(UncertaintyPrice agent,
			UncertaintyPrice master) {

		double[] valuesAgent = { agent.getCheap(), agent.getAverage(),
				agent.getExpensive() };

		double[] valuesMaster = { master.getCheap(), master.getAverage(),
				master.getExpensive() };
		double number = valuesAgent.length;

		double prior = calcEventResult(valuesAgent[0])
				+ calcEventResult(valuesAgent[1])
				+ calcEventResult(valuesAgent[2]);

		double post = calcEventResult(valuesMaster[0])
				+ calcEventResult(valuesMaster[1])
				+ calcEventResult(valuesMaster[2]);

		//System.out.println("\n\nAgent: " + agent.to_String());
		//System.out.println("Master: " + master.to_String());


		double result = (prior - post) / Math.log(number);
		//System.out.println("result: " + result + "\n\n");

		return result;

	}

	/**
	 * ------------------------------------------------------------------------
	 * Evaluates the Uncertainty value for the parameter Schedule
	 * ------------------------------------------------------------------------
	 * 
	 * @param agent
	 *            - Agent's knowledge for the parameter Schedule
	 * @param master
	 *            - Real Knowledge for the parameter Schedule
	 * @return - surprise value for the parameter Schedule
	 */
	public synchronized double evaluatingSchedule(UncertaintySchedule agent,
			UncertaintySchedule master) {

		double[] valuesAgent = { agent.getMorning(), agent.getAfternoon(),
				agent.getNight() };

		double[] valuesMaster = { master.getMorning(), master.getAfternoon(),
				master.getNight() };
		double number = valuesAgent.length;

		double prior = calcEventResult(valuesAgent[0])
				+ calcEventResult(valuesAgent[1])
				+ calcEventResult(valuesAgent[2]);

		double post = calcEventResult(valuesMaster[0])
				+ calcEventResult(valuesMaster[1])
				+ calcEventResult(valuesMaster[2]);

		//System.out.println("\n\nAgent: " + agent.to_String());
		//System.out.println("Master: " + master.to_String());


		double result = (prior - post) / Math.log(number);
		//System.out.println("result: " + result + "\n\n");

		return result;
	}

	/**
	 * Avoids the production of an undefined result.
	 * 
	 * @param e1
	 * @return a value
	 */
	private double calcEventResult(double e1) {
		if (e1 == 0) {
			return 0.0;
		} else {
			return -e1 * Math.log(e1);
		}
	}

}
